import json

from flask_login import current_user
from flask_sqlalchemy import SQLAlchemy
import app
import traceback
import logging

logger = logging.getLogger('app')

db = SQLAlchemy(app)


def safe_commit(db):
    try:
        db.session.commit()
        return True
    except:
        db.session.rollback()
        logger.info("数据库提交异常：%s", traceback.format_exc())
        return False


def safe_commit_return_error(db):
    try:
        db.session.commit()
        return True, ""
    except Exception as e:
        db.session.rollback()
        logger.info("数据库提交异常：%s", traceback.format_exc())
        return False, str(e.__dict__['orig'])


class QueryMaker:
    """
    配合前端框架的数据结构，组装查询、排序条件
    """

    def __init__(self, queryset):
        self.queryset = queryset  # 初始的queryset

        """
        filter_cfg结构：
        {
            "字段名":{
                "value":字段值,
                "model":字段model,
                "condition":筛选条件, //等于:==,小于<,小于等于<=,大于>,大于等于>=,不等于!=,属于in,不属于~in,包含contain
                "real_name":真实字段名,
                "lambda":改变v的lambda
            }
        }

        sorter_cfg结构：
        {
            "字段名":{
                "condition":"ascend",
                "model":model,
                "real_name":真实字段名
            }
        }
        """
        self.filter_cfg = dict()  # 过滤参数
        self.sorter_cfg = dict()  # 排序参数
        self.filter_keys = []  # 合法的filter字段名，不在其中的会被过滤，为空则不校验

    def add_filter(self, filter_data, default_model):
        """
        添加过滤参数，如果已有，则覆盖
        filter_data:{
            "key1":"值1",
            "key2":"值2",
            "key3":"值3",
        }
        default_model:默认的model
        """
        if isinstance(filter_data, str):
            filter_data = json.loads(filter_data)

        for k, v in filter_data.items():
            # 过滤非法字段
            if self.filter_keys:
                if k not in self.filter_keys:
                    continue
            self.filter_cfg[k] = {
                "value": v,
                "model": default_model,
                "condition": "==",
                "real_name": k,
                "lambda": None
            }

    def add_sorter(self, sorter_data, default_model):
        """
        添加排序参数
        sorter_data:{
            "字段1":"ascend", //升序
            "字段2":"descend" //降序
        }
        """
        if isinstance(sorter_data, str):
            sorter_data = json.loads(sorter_data)

        for k, v in sorter_data.items():
            self.sorter_cfg[k] = {
                "condition": v,
                "model": default_model,
                "real_name": k
            }

    def cfg_filter(self, key, condition=None, model=None, real_name=None,
                   lbd=None):
        """
        特殊配置需要定制的查询条件，不能配置不存在的key
        """
        if condition is None and model is None and real_name is None and lbd is None:
            return

        if condition and condition not in ["==", "<", ">", "<=", ">=", "!=", "is",
                                           "in", "~in", "contain"]:
            return

        if key not in self.filter_cfg:
            return

        if condition:
            self.filter_cfg[key]["condition"] = condition

        if model:
            self.filter_cfg[key]["model"] = model

        if real_name:
            self.filter_cfg[key]["real_name"] = real_name

        if lbd:
            self.filter_cfg[key]["lambda"] = lbd

    def cfg_sorter(self, key, condition=None, model=None, real_name=None):
        """
        特殊配置需要定制的排序条件，不能配置不存在的key
        """
        if condition is None and model is None and real_name is None:
            return

        if condition and condition not in ["ascend", "descend"]:
            return

        if key not in self.sorter_cfg:
            return

        if condition:
            self.sorter_cfg[key]["condition"] = condition

        if model:
            self.sorter_cfg[key]["model"] = model

        if real_name:
            self.sorter_cfg[key]["real_name"] = real_name

    def get_query(self):
        """
        组装query
        """
        condtions = []
        for k, v in self.filter_cfg.items():
            model = v["model"]
            condition = v["condition"]
            value = v["value"]
            k = v["real_name"]
            if v["lambda"]:
                value = v["lambda"](value)
            if condition == "==":
                condtions.append(getattr(model, k) == value)
            elif condition == "!=":
                condtions.append(getattr(model, k) != value)
            elif condition == "<":
                condtions.append(getattr(model, k) < value)
            elif condition == "<=":
                condtions.append(getattr(model, k) <= value)
            elif condition == ">":
                condtions.append(getattr(model, k) > value)
            elif condition == ">=":
                condtions.append(getattr(model, k) >= value)
            elif condition == "is":
                condtions.append(getattr(model, k).is_(value))
            elif condition == "in":
                condtions.append(getattr(model, k).in_(value))
            elif condition == "~in":
                condtions.append(getattr(model, k).notin_(value))
            elif condition == "contain":
                condtions.append(getattr(model, k).contains(value))
        query = self.queryset.filter(*condtions)

        sort_conditions = []
        for k, v in self.sorter_cfg.items():
            model = v["model"]
            condition = v["condition"]
            k = v["real_name"]
            if condition == "ascend":
                sort_conditions.append(getattr(model, k).asc())
            else:
                sort_conditions.append(getattr(model, k).desc())
        query = query.order_by(*sort_conditions)

        return query

global_models = dict()

def get_model(raw_model, db_name=None):
    """
    获取当前登录用户所属项目的model，主库
    """
    if db_name:
        cls_name = f"{raw_model.__name__}_{db_name}"
    else:
        cls_name = f"{raw_model.__name__}_{current_user.db_name}"
    return global_models.get(cls_name)


def get_slave_model(raw_model, db_name=None):
    """
    获取登录用户所属项目的model，从库，从库bind名称一定要加后缀_slave
    """
    if db_name:
        cls_name = f"{raw_model.__name__}_{db_name}_slave"
    else:
        cls_name = f"{raw_model.__name__}_{current_user.db_name}_slave"
    return global_models.get(cls_name)